package com.pansoft.openplanet.util;

import com.efounder.common.JInterceptor;
import com.efounder.constant.EnvironmentVariable;
import com.pansoft.openplanet.blockchain.util.StringUtils;

import org.json.JSONObject;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;

import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;

/**
 * 区块链相关服务请求的Token失效刷新拦截器
 *
 * @author wang
 */
public class TCTokenInterceptor implements Interceptor, JInterceptor {

    /**
     * 管理不同的刷新接口
     */
    public static HashMap<String, ITokenRefresh> refreshClassMap = new HashMap<>();

    static {
        refreshClassMap.put("tc.ipcom.io", new IPComTokenRefresh());
        refreshClassMap.put("tc.telecomm.io", new IPComTokenRefresh());
        //tc 山大测试服务器
        refreshClassMap.put("tcserver.openserver.cn", new IPComTokenRefresh());
        refreshClassMap.put("58.59.17.60", new IPComTokenRefresh());
    }


    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        //构建新情求
        Request newRequest = originalRequest.newBuilder().build();
        //执行请求
        Response response = chain.proceed(newRequest);
        //该Interceptor是否适用 //token是否失效
        if (isProcessAllowed(originalRequest) && isTokenExpired(response)) {
            //获取token，如果返回400或出错，则返回这个Response
            Response tokenResponse = getTokenRefreshResponse(originalRequest);
            if (tokenResponse == null) {
                return response;
            }
            if (tokenResponse.code() == 400 || tokenResponse.body() == null) {
                return tokenResponse;
            }
            //请求token成功，修改request，继续请求
            //获取tokenResponse, 解析，如果有refreshToken not exists，那么修改code=400返回
            //因为response的body智能消耗一次
            String tokenResponseString = tokenResponse.body().string();
            try {
                JSONObject jsonObject = new JSONObject(tokenResponseString);
                if (jsonObject.has("error_description") &&
                        jsonObject.optString("error_description").equals("refreshToken not exists")) {
                    return tokenResponse.newBuilder().code(400).build();
                }
            } catch (Exception e) {
                e.printStackTrace();
                return response;
            }
            Request request = getAfterRefreshRequest(originalRequest, tokenResponseString);
            if (request == null) {
                return response;
            }
            //重新请求
            return chain.proceed(request);
        }
        //不适用Interceptor，直接返回原Response
        return response;
    }

    private Response getTokenRefreshResponse(Request request) {
        String hostName = request.url().host();
        ITokenRefresh iTokenRefresh = refreshClassMap.get(hostName);
        Response response = iTokenRefresh.getRefreshToken(request);
        return response;
    }

    /**
     * 根据request的域名，从map中获取实现刷新接口的类，进行刷新，返回request
     *
     * @param responseString token刷新返回的response string
     * @param request        原来的请求request，修改后返回
     * @return request
     */
    private Request getAfterRefreshRequest(Request request, String responseString) {
        try {
            JSONObject jsonObject = new JSONObject(responseString);
            if (jsonObject.has("access_token")) {
                String newAccessToken = jsonObject.getString("access_token");
                String newRefreshToken = jsonObject.getString("refresh_token");
                //请求token成功，将token保存在EV中
                EnvironmentVariable.setProperty("tc_access_token", newAccessToken);
                EnvironmentVariable.setProperty("tc_refresh_token", newRefreshToken);
                //通过header加入请求的token
                if (!StringUtils.isEmpty(newAccessToken)) {
                    return modifyAddParas(request, "access_token", newAccessToken);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 往map里增加其他项目自己实现的刷新接口类
     *
     * @param key 域名
     */
    public static void addClassToRefreshMap(String key, ITokenRefresh iTokenRefresh) {
        refreshClassMap.put(key, iTokenRefresh);
    }

    /**
     * 刷新完成后，获取token，将新token重新拼入request的请求参数中
     *
     * @param request   request
     * @param paramName token参数名，如access_token
     * @param token     token
     * @return request
     */
    public static Request modifyAddParas(Request request, String paramName, String token) {
        if ("GET".equals(request.method())) {
            //如果是get请求
            HttpUrl url = request.url();
            HttpUrl newUrl = url.newBuilder()
                    .setEncodedQueryParameter(paramName, token)
                    .build();
            return request.newBuilder()
                    .url(newUrl).build();
        } else if (request.body() instanceof FormBody) {
            // 构造新的请求表单
            FormBody.Builder formBuilder = new FormBody.Builder();

            FormBody body = (FormBody) request.body();
            //将以前的参数添加
            for (int i = 0; i < body.size(); i++) {
                formBuilder.add(body.encodedName(i), body.encodedValue(i));
            }
            //追加新的参数
            formBuilder.add(paramName, token);
            //构造新的请求体
            return request.newBuilder().post(formBuilder.build()).build();
        }
        return null;
    }

    /**
     * 判断请求的token是否失效
     *
     * @param response response
     */
    private boolean isTokenExpired(Response response) {
        if (response.code() == 401) {
            return true;
        }
        try {
            if (response.body() == null) {
                return false;
            }
            String responseString = readResponseWithoutConsum(response);
            JSONObject jsonObject = new JSONObject(responseString);
            if (jsonObject.has("result") && jsonObject.getString("result").equals("fail")
                    && jsonObject.has("msg") && jsonObject.getString("msg").equals("invalid_token")) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private String readResponseWithoutConsum(Response response) {
        try {
            ResponseBody responseBody = response.body();
            BufferedSource source = responseBody.source();
            source.request(Long.MAX_VALUE); // Buffer the entire body.
            Buffer buffer = source.getBuffer();
            return buffer.clone().readString(StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Interceptor getInterceptor() {
        return this;
    }

    @Override
    public boolean isProcessAllowed(Request request) {
        //如果这个map里维持着当前请求的host，那么使用该Interceptor
        String hostName = request.url().host();
        return refreshClassMap.containsKey(hostName);
    }

    interface ITokenRefresh {
        Response getRefreshToken(Request originRequest);
    }
}
